//const mg2 = require("../old/mg2");
// should be referred tro as rich-trailmarked-text editor
(function () {
var path
async function initLocalforage() {
if (!window.lfDOTS) {
window.lf = parent.localforage
window.lfDOTS = window.lf.createInstance({
name: 'DOTS',
storeName: 'dots'
});
}
return window.lfDOTS
}
// initLocalforage()
function formatDoc(oDoc, sCmd, sValue) {
if (!validateMode(oDoc)) {
return;
}
document.execCommand(sCmd, false, sValue);
//- ftp : automatically set foreground color white for blue green background
if (sCmd === 'backcolor' &&
(sValue === 'red' || sValue === 'green' || sValue === 'blue')) {
console.log('change foregraound to white')
document.execCommand("forecolor", false, "white");
}
oDoc.focus();
}
function validateMode(oDoc) {
if (!document.getElementById("rte-mode-" + rId.exec(oDoc.id)[0]).checked) {
return true;
}
alert("Uncheck \u00AB" + sModeLabel + "\u00BB.");
oDoc.focus();
return false;
}
function extractText(oDoc) {
if (oDoc.innerText) {
return oDoc.innerText;
}
var oContent = document.createRange();
oContent.selectNodeContents(oDoc.firstChild);
return oContent.toString();
}
function setDocMode(oDoc, bToSource) {
window.oDoc = oDoc
if (bToSource) {
var oContent = document.createTextNode(oDoc.innerHTML), oPre = document.createElement("pre");
oDoc.innerHTML = "";
oDoc.contentEditable = false;
oPre.className = "rte-sourcetext";
oPre.id = "rte-source-" + oDoc.id;
oPre.onblur = oDoc.onblur;
oPre.contentEditable = true;
oPre.appendChild(oContent);
oDoc.appendChild(oPre);
} else {
oDoc.innerHTML = extractText(oDoc);
oDoc.contentEditable = true;
}
oDoc.focus();
}
function menuSelect() {
if (this.selectedIndex < 1) {
return;
}
if (this.id.startsWith("extra")) {
sCmd = this.id.slice(0, -1)
let option = this[this.selectedIndex]
let sAction = option.value
handleExtra(sCmd, sAction)
this.selectedIndex = 0;
return 0
}
var sMenuGroup = rId.exec(this.id)[0], sCmd = this.id.slice(0, -sMenuGroup.length);
formatDoc(aEditors[sMenuGroup], sCmd, this[this.selectedIndex].value);
this.selectedIndex = 0;
}
function handleExtra(sCmd, sAction) {
let selection = getSelection()
let parentNode = selection.rangeCount > 0 ? selection.getRangeAt(0).commonAncestorContainer.parentNode : null
let handler = {
"expand": function (node) {
$(node).siblings().toArray().splice(0).map(function (i) { $(i).show() })
},
"collapse": function (node) {
$(node).siblings().toArray().splice(0).map(function (i) { $(i).hide() })
},
"anchor": function (node) {
//- issue : add anchor for clue
//- fix : remove spaces from anchorName
// show anchorName in title
let anchorName = node.innerText.substring(0, 24).replace(/ /g, "")
let anchor = '$ '
document.execCommand('insertHtml', false, anchor)
console.info("inserted anchor " + node.innerText.substring(24))
},
}
let munger = {
"collapseAll": function () {
$('ul li').hide()
// x = $('ul').toArray()
// x.map(function (z) { $('li', z).first().show() })
},
"expandAll": function () {
$('li').show()
$('ul').show()
// $('ul li').hide()
x = $('ul').toArray()
x.map(function (z) {
$('li').hide()
$('li', z).first().show()
})
},
"clean": function () {
opidox.rte.cleanElem('div[style]')
},
//- feat : opidox.rte.interpretPropOnPage
" - i ": function () {
let choice = confirm("Would ypu like to execute property marks on the")
if (choice) {
opidox.rte.interpretPropOnPage('i')
}
}
}
munger[sAction]()
if (parentNode) {
(handler[sAction])(parentNode)
}
}
function buttonClick() {
var sBtnGroup = rId.exec(this.id)[0], sCmd = this.id.slice(0, -sBtnGroup.length);
var cc = 0
if (sCmd === "count") {
let selection = window.getSelection().toString()
console.log(selection)
if (selection) {
cc = selection.length
spacesRemoved = selection.replace(/ /g, '').length
wordCount = cc - spacesRemoved
countTodisplay = cc + " w" + wordCount
$('.ccSpan').text(countTodisplay)
document.execCommand("copy");
window.getSelection().empty()
}
else {
$('.ccSpan').text($('.rte-editbox').text().length)
}
return
}
customCommands.hasOwnProperty(sCmd) ? customCommands[sCmd](aEditors[sBtnGroup]) : formatDoc(aEditors[sBtnGroup], sCmd, this.alt || false);
}
function changeMode() {
setDocMode(aEditors[rId.exec(this.id)[0]], this.checked);
}
function updateField() {
var sFieldNum = rId.exec(this.id)[0];
document.getElementById("rte-field-" + sFieldNum).value = document.getElementById("rte-mode-" + sFieldNum).checked ? extractText(this) : this.innerHTML;
}
function createMenuItem(sValue, sLabel) {
var oNewOpt = document.createElement("option");
oNewOpt.value = sValue;
oNewOpt.innerHTML = sLabel || sValue;
return oNewOpt;
}
function createEditor(oTxtArea) {
var nEditorId = aEditors.length, oParent = document.createElement("div"),
oMenuBar = document.createElement("div"),
oToolsBar = document.createElement("div"), oEditBox = document.createElement("div"),
oModeBox = document.createElement("div"), oModeChB = document.createElement("input"),
oModeLbl = document.createElement("label");
oParent.className = "rich-text-editor";
oParent.id = oTxtArea.id || "rich-text-" + nEditorId;
oMenuBar.className = "rte-menus";
oToolsBar.className = "rte-tools";
oEditBox.className = "rte-editbox";
oEditBox.id = "rte-editbox-" + nEditorId;
oEditBox.contentEditable = true;
oEditBox.innerHTML = oTxtArea.value;
aEditors.push(oEditBox);
if (oTxtArea.form) {
var oHiddField = document.createElement("input");
oHiddField.type = "hidden";
oHiddField.name = oTxtArea.name;
oHiddField.value = oEditBox.innerHTML;
oHiddField.id = "rte-field-" + nEditorId;
oTxtArea.form.appendChild(oHiddField);
oEditBox.onblur = updateField;
}
for (var oMenu, oMenuOpts, vOpt, nMenu = 0; nMenu < oTools.menus.length; nMenu++) {
oMenu = document.createElement("select");
oMenu.id = oTools.menus[nMenu].command + nEditorId;
oMenu.onchange = menuSelect;
oMenu.appendChild(createMenuItem(oTools.menus[nMenu].header));
oMenuOpts = oTools.menus[nMenu].values;
if (oMenuOpts.constructor === Array) {
for (vOpt = 0; vOpt < oMenuOpts.length; oMenu.appendChild(createMenuItem(oMenuOpts[vOpt++])));
} else {
for (vOpt in oMenuOpts) {
oMenu.appendChild(createMenuItem(vOpt, oMenuOpts[vOpt]));
}
}
oMenu.selectedIndex = 0;
oMenuBar.appendChild(document.createTextNode(" "));
oMenuBar.appendChild(oMenu);
}
for (var oBtnDef, oButton, nBtn = 0; nBtn < oTools.buttons.length; nBtn++) {
oBtnDef = oTools.buttons[nBtn];
oButton = document.createElement("img");
oButton.className = "rte-button";
oButton.id = oBtnDef.command + nEditorId;
oButton.src = oBtnDef.image;
if (oBtnDef.hasOwnProperty("value")) {
oButton.alt = oBtnDef.value;
}
oButton.title = oBtnDef.text;
oButton.onclick = buttonClick;
oToolsBar.appendChild(oButton);
}
// add a span to hold count
var countSpan = document.createElement("b");
countSpan.className = "ccSpan";
oToolsBar.appendChild(countSpan)
oModeBox.className = "rte-switchmode";
oModeBox.title = sModeLabel;
oModeChB.type = "checkbox";
oModeChB.id = "rte-mode-" + nEditorId;
oModeChB.onchange = changeMode;
// oModeLbl.setAttribute("for", oModeChB.id);
// oModeLbl.innerHTML = sModeLabel;
oModeBox.appendChild(oModeChB);
oModeBox.appendChild(document.createTextNode(" "));
oModeBox.appendChild(oModeLbl);
oParent.appendChild(oMenuBar);
oParent.appendChild(oToolsBar);
oParent.appendChild(oEditBox);
oMenuBar.appendChild(oModeBox);
oTxtArea.parentNode.replaceChild(oParent, oTxtArea);
// gyuri
var editArea = $('#' + oTxtArea.id);
editArea.addClass("scrolling")
editArea.bind('DOMNodeInserted', function (event) {
if (event.originalEvent && event.originalEvent.target) {
var target = $(event.originalEvent.target);
//now you can check what has been moved
}
});
$('.rich-text-editor').css({ "width": (window.innerWidth - 40) + 'px' })
$('.rte-editbox').css({ "width": (window.innerWidth - 50) + 'px' })
}
function replaceFields(nFlag) {
nReady |= nFlag;
if (nReady !== 3) {
return;
}
for (
var oField, nItem = 0, aTextareas = Array.prototype.slice.call(document.getElementsByTagName("textarea"), 0);
nItem < aTextareas.length;
oField = aTextareas[nItem++], oField.className !== "rich-text-editor" || createEditor(oField)
);
; opidox.rte.setup()
}
function toolsReady() {
oTools = JSON.parse(this.responseText);
replaceFields(2);
}
function documentReady() {
replaceFields(1)
}
var oTools, nReady = 0, sModeLabel = "Show HTML", aEditors = [], rId = /\d+$/, oToolsReq = new XMLHttpRequest(),
customCommands = {
"printDoc": function (oDoc) {
if (!validateMode(oDoc)) {
return;
}
var oPrntWin = window.open("", "_blank", "width=450,height=470,left=400,top=100,menubar=yes,toolbar=no,location=no,scrollbars=yes");
oPrntWin.document.open();
oPrntWin.document.write("
Print<\/title><\/head> " + oDoc.innerHTML + "<\/body><\/html>");
oPrntWin.document.close();
},
"cleanDoc": function (oDoc) {
if (validateMode(oDoc) && confirm("Are you sure?")) {
oDoc.innerHTML = "";
}
;
},
"createLink": function (oDoc) {
let selection = window.getSelection().toString()
var sLnk = prompt("Write Dot Title/URL ", selection);
let target = sLnk
if (sLnk) {
//- fn : ensure link target does not have leading/trailing white space
let target = sLnk.trim()
if (!sLnk.startsWith("http")) {
let newDotLink = "/wiki?t=" + selection
if (newDotLink) {
target = newDotLink
//- ftp : dead wood
opidox.rte.action.createDot(selection, sLnk)
}
}
formatDoc(oDoc, "createlink", target);
}
},
"save": function () {
opidox.rte.save()
//- ftp : RTE setup on save and indicate saved status
opidox.rte.setup()
$('#isSaved').attr('checked', true)
//window.minddrive.save2MindDrive(dot)
// opener.hostapp.run('/minddrive/save', n)
}
};
oToolsReq.onload = toolsReady;
oToolsReq.open("GET", "rich-text-tools.json", true);
oToolsReq.send(null);
window.addEventListener ? addEventListener("load", documentReady, false) : window.attachEvent ? attachEvent("onload", documentReady) : window.onload = documentReady;
})();
window.opidox = window.opidox || {}
opidox.rte = (function () {
let _rte = {}
let n;
//- fix : When running in trailNext there is no parent iframe
let oldTrailMarks = true
//- fix : access to mg2 in editor
try {
if (parent.mg2) {
parent.parent.dot = parent.mg2.G2
oldTrailMarks = true
mg3 = mg2 || parent.mg2
}
}
catch (e) { }
function hideSubLists() {
$('ul>ul').hide()
}
//- ftp : toggle top level clues
function toggle2(ev) {
console.log("toggle2", ev.offsetX)
//- issue : Prevent top level clue collapsing
if (ev.offsetX > 13 && ev.ctrlKey) {
// console.log("here")
listItemAction(ev, ev.target)
return
}
if (ev.offsetX < 13) {
let next = $(ev.target).next()
//console.log(next.show())
let firstChild = next
if ($(ev.target).is('span')) {
firstChild = $(ev.target.parentElement).next()
}
if (next.is('div')) {
firstChild = next.children().first()
}
if (firstChild && firstChild.is('ul')) {
if (firstChild && firstChild.is(':visible')) {
firstChild.hide()
}
else {
firstChild.show()
}
return false
}
}
else { return false }
}
//- obsolated : toggle - by : - ftp : toggle top level clues
function toggle(ev) {
// hideSubLists()
return
console.log("one", ev.offsetX)
let next = $(ev.target).next()
//console.log(ev.offsetX)
if (ev.offsetX > 13 && ev.ctrlKey) {
// console.log("here")
listItemAction(ev, ev.target)
return
}
else { return }
// Stop expanding next item if it is a list
if (ev.target.tagName === 'LI' && $(ev.target).next()[0].tagName === 'LI') {
return
}
let listItem = ev.target.tagName === 'LI' ? $(ev.target) : $(ev.target).parent()
if (listItem.next()[0].style.display === "none") {
listItem.next().show()
}
else {
listItem.next().hide()
}
$('ul', listItem.next()).show()
// show character and wordcount when toggling blog
let selection = listItem.children();
//- fix : check for non empty array
if (selection && selection.length > 0) {
selection.toArray().reduce(function (a, b) {
return a + $.trim($(b).text())
})
cc = selection.length
console.log(selection)
spacesRemoved = selection.replace(/ /g, '').length
wordCount = cc - spacesRemoved
countTodisplay = cc + " w" + wordCount
$('.ccSpan').text(countTodisplay)
}
}
function listItemAction(ev, li) {
//console.log($(li).html())
// before toggline
// check for shift key
if (ev.ctrlKey) {
let x = $(ev.target).text()
if (x) {
let action = x.split(':')[0].split('-')[1].trim()
function handleIntent(action) {
let intents = {}
let intent = intents[action]
if (!intent) {
function showContext(target) {
let jqe = $(target)
console.log(jqe.html())
}
showContext($(ev.target).parent())
}
}
handleIntent(action)
alert(action)
}
return true
}
}
function clickerForTop() {
//- ftp : toggle top level clues
$('div', $('#rte-editbox-0')).click(toggle2)
$('li').click(toggle2)
$('li').toArray().forEach(function (e) {
let highlightColor = localStorage.HIGHLIGHT_COLOR
if (!localStorage.HIGHLIGHT_COLOR) {
localStorage.HIGHLIGHT_COLOR = '#DDDDFF'
}
if (e.nextElementSibling && e.nextElementSibling.tagName === "UL") {
$(e).css("background-color", localStorage.HIGHLIGHT_COLOR)
}
/*
if (e.parentElement.firstElementChild.tagName==="LI") {
$(e.parentElement.firstElementChild).css("background-color","#FAFAFF")
}
console.log(e)
*/
})
/*
$('li').toArray().forEach(function (e) {
console.log(e)
})
*/
}
function setupAnnotationSearch() {
// trigger memex search
var p = $('ul.wbs li');
$('.annotationTrigger', p).remove()
p.each(function (x, e) {
let text = e.innerText
text = text.trim()
text = text.replace(/[\n\r]+|[\s]{2,}/g, '+')
text = text.replace(/ /g, '+')
let targetLocation = 'chrome-extension://abkfbakhjpmblaafnpgjppbmioombali/options.html#/overview?query='
+ text
let open = "window.open('" + targetLocation + "','_self')"
// open = 'location.href='
let link2memexSearch = $('' +
' ' + ' ')
e.append(link2memexSearch[0])
})
/*
p.attr('unselectable', 'on')
.css('user-select', 'none')
.on('selectstart', false);
p.dblclick(function (e) {
let li = $(e.target)
let text =li.text()
text = text.replace(/[\n\r]+|[\s]{2,}/g, '+')
text ="Chromium"
let memexSearch = "chrome-extension://abkfbakhjpmblaafnpgjppbmioombali/options.html#/overview?query=" + text
openInNewTab(memexSearch)
$(e).attr('unselectable', 'on')
.css('user-select', 'none')
.on('selectstart', false);
p.css("cursor", "text")
.attr('contenteditable', true)
.attr('unselectable', 'off')
.css('user-select', 'inherit')
.off('selectstart', false)
.focus();
});
// setup a click handler
// $('li').dblclick(function (ev) {
// console.log(ev)
// })
*/
}
//- feat : convert data0images in slides
_rte.setup = async function (dot) {
let hubOrigin = 'http://localhost:8080'
function sendRequestViaOpenChannel(cont) {
let indieHubFrame = document.getElementById("IndieHubFrame")
if (false && !indieHubFrame.src) {
indieHubFrame.src = host + "/hub" + location.search + "&ts=" + moment().unix()
indieHubFrame.contentWindow.addEventListener('load', function () {
cont(hub.scld.x.getDrone())
}, false)
}
}
// retrofit
if (screen.availHeight < 801) {
$('.rte-editbox').css("max-height", "600").css("width", "480px")
//alert("x2e48")
}
/*
if (!dot) {
if (oldTrailMarks) {
//- ftp : access mg2 from parent
n = parent.mg2.G2.getFocus().n()
}
else {
n = mg2.dot.getFocus()
}
}
*/
let ps = new URLSearchParams(location.search.substring(1))
let t = ps.get('t')
if (!t) {
t = location.search.substring(1)
}
/*
else {
path = ps.getAll('path')
if (path.lengt>0) {
path = path[0]
}
else {path = ""}
}
*/
if (t) {
let td = decodeURIComponent(t)
//- bug : sending back received dot
let title = decodeURIComponent(t)
let dots = mindgraph.dot.byTitle(title, true)
//- ftp : no dot matching title found
if (dots.length === 0) {
//TODO get is scribe
// create dot that does not exists here
let dot = {
t: decodeURIComponent(title),
s: "stub - " + title,
i: "https://bafybeihvcrddb4zbq5t4zuj7q4esabf5mizoxvkjvoac7gmmf73fcnqou4.ipfs.w3s.link/dot.png"
}
dots = [mindgraph.dot.save(dot)]
return
// - fn : sendRequestViaOpenChannel
// sendRequestViaOpenChannel(function (drone) {
const rq = 'getByTitle'
const from = localStorage.peerName
const to = 'scribe'
const title = t
const m = { rq, from, to, title }
// drone(JSON.stringify(m))
// window.hub.scld.x.queueMessage(JSON.stringify(m))
debugger
//TODO : clarify host
if (true || location.host === "indyhub1.fission.app") {
hubOrigin = location.origin
hubOrigin = location.origin + location.pathname
}
debugger
open(hubOrigin + './hub/chat/?' + encodeURIComponent(JSON.stringify(m)))
// hub.scld.x.add(message)
// })
return
}
if (dots.length === 1) {
n = dots[0]
}
if (dots.length > 0) {
//- fix : handling unique dots
let dots2 = mindgraph.dot.byTitle(decodeURIComponent(t), true)
if (dots2.length === 1)
n = dots2[0]
}
//- ftp : alert if match by title is not unique
else {
alert("title is not unique")
console.log(dots)
}
}
if (!n) {
// location.href = '/demo/#dot/search/' + t
return
}
// - ftp : Make stub editable in RTE
let dotSize = encodeURIComponent(JSON.stringify(n)).length
let stubEdit =
' ' +
'SAVE ' +
' share' +
' with provenance' +
'slides ' +
'WCG ' +
'' + dotSize + ' '
//- issue : - add : self link to dot shown in editor
//- ftp : display time created
//- TODO : ensure ct exist in MindGraph
if (!n.le) {
if (n.lu) {
n.le = n.lu
}
}
//TODO del with turning off
//REMEMBER to turn off shared status of node when replicated in push
let timeLastEdited = moment(parseInt(n.le) * 1000).format("YYYY MMM DD hh:mm")
let timeCreated = ""
if (n.ct) {
timeCreated = moment(parseInt(n.ct) * 1000).format("YYYY MMM DD")
}
//- issue : show if saved and prevent reload if edited but not saved
//- fix : links for module with ../ and ?
let selfLink = '' + timeLastEdited + ' '
let dragLink = '' + n.t + ' '
let hypermap = '' + 'hypermap' + ' '
let shared2 = ''
let headerShow = '' + shared2 +
'
' + n.t + ' ' +
'
Home '
+ hypermap +
n.a + ' ' + timeCreated + ' ' + selfLink + '
' +
'
' + stubEdit + dragLink
// '' + stubEdit + ' ' + n.a + '
'
$('#dotName').html(headerShow)
//- ftp : edit icon shown on tab
// for
//- feat : Present Page Intent in Tab
let spaceIndex = n.s.indexOf(' ')
if (spaceIndex < 0) {
spaceIndex = 2
}
//- fix : pagemrk icon showing
const stubInitial = n.s.substring(2, spaceIndex)
const stubMark = n.s.substring(0, 2)
let title = n.t
const index = n.t.indexOf(' - ')
let pageMark
if (index > 0) {
title = n.t.substring(index + 3)
pageMark = stubMark + stubInitial + ' ' + title
}
else {
pageMark = stubInitial + stubMark + title
}
$('title').text(pageMark)
$('#stub').val(n.s)
//- ftp : show dot.pa.shared2
/** show emojis for conversants with whom the page had been shared with */
let sharedToList = ''
if (n.pa && n.pa.shared2) {
sharedToList = n.pa.shared2.reduce(function (a, b) {
return a + b.substring(0, 2) + ' '
}, '')
}
$('#sharedToList').html(sharedToList)
//- ftp : show icon for dot topic
let iconSrc = n.i
//- ftp : use dot image or first image on page as icon for tab
//- fix : ensure enclosing div for jquery img search
try {
let imgElements = $('img', '' + n.b + '
')
if (imgElements && imgElements.length > 0) {
iconSrc = imgElements[0].src
}
}
catch (e) { console.error(e) }
//- web - how : set favicon dynamically
$('link[rel="icon"]').attr('href', iconSrc)
console.log(n.b)
function bgetBodyLinkHref(bodyLink) {
const bodyLinkPrefix = 'body<'
const endBodyLinkPosition = bodyLink.indexOf(endBodyLinkMatch)
const bodyLinkHref = bodyLink.substring(bodyLinkPrefix.length, endBodyLinkPosition)
return bodyLinkHref
}
if (n.b && n.b.startsWith(' ' + bodyProps.b + '')
$('img', b2).each(function (i, x) {
if (x.width > innerWidth) {
$(x).addClass("large"). // fitting large images into editor
css({ "max-width": "80%", "display": "block", "margin": "auto" })
}
}
)
// let html = formatFactory(b2.html())
let html = b2.html()
if (!html.trim().startsWith('<')) {
html = '' + html + '
'
}
html = formatFactory(html)
$("#rte-editbox-0").html(html)
// fitting large images into editor
$('img.large').css({ "max-width": "80%", "display": "block", "margin": "auto" })
/*
document.onmouseup = document.onkeyup = document.onselectionchange = function () {
let text = opidox.rte.getSelectionText();
console.log(text)
}
*/
// hideSubLists()
clickerForTop()
setupAnnotationSearch()
function setupPasteEventHandler() {
$("#rte-editbox-0").on('paste', async function (ev) {
window.x = await navigator.clipboard.readText()
})
}
//- ftp : reflect shared status
if (n.shared) {
$('#shareCheckBox').prop('checked', true)
}
/**
* - issue : add linkClicked even hadler
*/
setupLinkClickeHandlers()
function setupLinkClickeHandlers() {
$('a').on('click', linkClicked)
function linkClicked(ev) {
let target = ev.target
//- ftp : retorfit wiki links
// using drag and drop links to dot into page creates link with full url
// TODO : fix it in the editor on page load
//- fix : only mungle local
debugger
/** jnk
let path = target.href
path = path.replace(/wiki\?/, "./rte/?")
debugger
if (target.origin === location.host) {
const origin = target.origin
path = target.href.substring(origin.length)
}
*/
let path = location.origin + location.pathname + target.search
let w = window.open(path, '_blank');
// w.hostapp = hostapp
}
}
// limit max-width of images
// allow copy paste of code snippets
$('.nowrap').css("white-space", "nowrap")
window.trailmarker.setup()
$('#rte-editbox-1').focus()
// - ftp : scroll to anchor
if (location.hash) {
let anchorText = location.hash.substring(1)
let anchorEl = $('a[name="' + anchorText + '"]')
//- ftp : check for anchor element position
if (anchorEl.position()) {
//https://hyp.is/4EB56Cq5Eey7-P98vI4YoQ/stackoverflow.com/questions/1605698/text-blinking-jquery
let blinkTime = 500
let top = anchorEl.position().top - 300
console.log(top)
//- ftp : slide to anchor element and blink
$('.rte-editbox').animate({ scrollTop: top }, 1000);
anchorEl.animate(4000, "linear", function () {
let target = this.parentElement
$(target).animate({ opacity: 0 }, blinkTime);
$(target).animate({ opacity: 1 }, blinkTime);
$(target).animate({ opacity: 0 }, blinkTime);
$(target).animate({ opacity: 1 }, blinkTime);
$(target).animate({ opacity: 0 }, blinkTime);
$(target).animate({ opacity: 1 }, blinkTime);
});
history.replaceState(null, null, '/wiki' + location.search + location.hash)
}
}
// let webStorageIframe = document.getElementById("Web3Frame")
// webStorageIframe.src = '/web3/' + '?' + moment().unix()
// $('#Web3Frame').show()
//- ux : add SAVE button
$('#saveBtn').click(function () {
_rte.save()
_rte.setup()
$('#isSaved').attr('checked', true)
})
//- ux : toggle share status
//- ftp : reflect shared status
$('#shareCheckBox').click(function () {
if ($('shareCheckBtn').is(':checked')) {
}
else {
delete n.shared
}
})
if (navigator.platform==="Win32") {
//alert("x")
$('#rte-editbox-0').width(720)
}
}
//- fn : munge image src attribute to point to git repo
window.foam2dotBody = function () {
let githubRepo = 'https://raw.githubusercontent.com/gyuri-lajos/gyuri/master/attachments/'
$('#rte-editbox-0 img').each(function () {
x = this.src.split('/');
this.src = githubRepo + x[x.length - 1]
})
}
_rte.clickerForTop = clickerForTop
_rte.getNodeLoaded = function () {
let dot = mindgraph.dot.byId(n.a)
dot.b = dot.b.replace(/\n[ ]+/g, '\n ')
return dot
}
_rte.getNodeAsEdited = function () {
let nEdited = n
if (!n) {
return n
}
// make all lists visible
$('ul').show()
// remove annotation links
$(".annotation").remove()
//- issue : on Save in RTE clear highlighting of leaf list items
// remove all styles
$('li[style]').toArray().forEach(function (x) { $(x).removeAttr("style") })
nEdited.b = $("#rte-editbox-0").html();
nEdited.b = nEdited.b.replace(/\n[ ]+/g, '\n ')
//-ftp : Make stub editable in RTE
let stubText = $('#stub').val()
nEdited.s = stubText
return nEdited
}
_rte.getChangesForNode = function () {
let nEdited = this.getNodeAsEdited()//.replace(/\n[ ]+/g,'\n ')()
if (!nEdited) {
return ''
}
console.log(nEdited)
const nOriginal = this.getNodeLoaded()//.replace(/\n[ ]+/g,'\n ')
console.log(nOriginal)
let changes = {
o2n: this.getDiffsBetweenNodes(nOriginal, nEdited).trim(),
n2o: this.getDiffsBetweenNodes(nEdited, nOriginal).trim()
}
return Object.values(changes).reduce(function (a, b) { return a + b }, '')
}
// - for : key insight - TrailMarks
// fn : rte.getDiffsBetweenNodes
_rte.getDiffsBetweenNodes = function (n1, n2) {
// - annote : https://hypothes.is/a/xNSn9IcxEeyJuScG-WqWiQ
function diffStrings(x, y) {
let diff = [...x].filter((v, idx) => [...y][idx] !== v);
return diff.reduce(function (a, b) { return a + b }, "")
}
function diffProps(a, b, props) {
let arrays = props.map(function (prop) {
return diffStrings(a[prop], b[prop])
})
return arrays.reduce(function (a, b) { return a + b })
}
return diffProps(n1, n2, ["t", "s", "b"])
}
_rte.save = function () {
// make all lists visible
$('ul').show()
// remove annotation links
$(".annotation").remove()
//- issue : on Save in RTE clear highlighting of leaf list items
// remove all styles
$('li[style]').toArray().forEach(function (x) { $(x).removeAttr("style") })
n.b = $("#rte-editbox-0").html();
//-ftp : Make stub editable in RTE
let stubText = $('#stub').val()
n.s = stubText
console.log(stubText)
n.creator = localStorage.user
//- ftp : save body tow web3
mindgraph.dot.update(n);
// Q&D generate slides
localStorage.slides = m.u.doSlides(n)
//- Q&D : svae curent node anchor when generating slides
// so that we can get the image for the dot when processing /reveal?/slides
localStorage.CN = n.a
// hide nested lists so that only top level items can be seen
// $('ul>ul').hide()
/*
if (oldTrailMarks && parent.opidox.rte4mg) {
parent.opidox.rte4mg.action.updateHTML4DOT(n)
}*/
//- issue : on page save in editor replicate across devices
async function replicateViaOpenChannel(n) {
// window.hostapp.run('/replicate', n)
// dim.
// window.hostapp.run('#replicate',n)
async function createPushEvent(n) {
let origDot = JSON.parse(JSON.stringify(n))
let message
//- step : append first character in peerName to anchor for node
function getPeerName() {
return localStorage.peerName
}
function compactPageBodyHtml(body) {
return body.replace(/ /g, ' ')
}
n.b = compactPageBodyHtml(n.b)
let encoded = encodeURIComponent(n.b);
//TODO consider converting to markdown for transfer
if (encoded.length > 10000) {
alert("encoded body larger than limit" + encoded.length)
// return
}
else {
alert("encoded length " + encoded.length)
}
//- QD set shared to true on dot
n.shared = moment().format("YYYY MM DD hh:mm")
const peerName = getPeerName()
const peerEmoji = peerName.substring(0, 2)
n.a = n.a + peerEmoji
n.t = n.t + ' ' + peerEmoji
const from = localStorage.peerName
const event = 'push'
const action = 'save'
const to = "all"
//- ftp : warning on large body
console.log(n.b.length)
let sizeLimit = 10000
let provenance = $('#provenance').is(':checked')
debugger
if (provenance || encoded.length > sizeLimit) {
//- feat : save body to web3storage
//- ftp : dynamically loading Web3Frame
debugger
let web3StorageIframe = document.getElementById("Web3Frame")
debugger
web3StorageIframe.src = location.pathname + '../web3/' + '?' + moment().unix()
//- ftp : increase height of web3StorageIframe before loading
web3StorageIframe.height = "520px"
debugger
web3StorageIframe.addEventListener('load', async function () {
let bodyLink = await web3storage.store.body(n, window.wweb3p)
//- feat : unshift bodyLinks to dot.bsl array
n.blsa = n.blsa || []
n.blsa.unshift(bodyLink)
origDot.blsa = n.blsa
window.mindgraph.dot.update(n)
window.mindgraph.dot.update(origDot)
n.b = ` body `
const data = [n]
message = JSON.stringify({ event, action, from, to, data })
//hub.scld.x.add(message)
//- feat : invoke webnative intent hub chat as fetch get request
debugger
open(location.pathname + '../hub/chat/?' + encodeURIComponent(JSON.stringify(message)))
})
}
else {
if (true) {
// fall through to create push event
const data = [n]
message = JSON.stringify({ event, action, from, to, data })
//hub.scld.x.add(message)
debugger
let href = location.origin + location.pathname + '../hub/chat/?'
open(href + encodeURIComponent(message), "chat")
//- fix : SclaDrone size limit
window.hub.odb.setupOwnHub('', async function (db) {
const hash = await db.add([n])
//- ftp : replace body of dot with hash in message sent via cladrone
n.b = "- hash : " + hash
//- ftp : set hs property to an array of hashes in reverse chronological order
n.hs = n.hs || []
n.hs.push(hash)
const data = [n]
const message = JSON.stringify({ event, action, from, to, data, hash })
$('#log').append(message)
// replaced by open window
// hub.scld.x.add(message)
open(location.pathname + '../hub/chat/?' + encodeURIComponent(JSON.stringify(message)))
})
}
}
}
debugger
createPushEvent(n)
}
//Q&D shared property is set so share again
let share = $('#shareCheckBox').is(':checked') || n.shared;
if (share) {
// allways replicate via open channel
replicateViaOpenChannel(n)
return
//- ftp : load IndyHubIframe on save
let indieHubFrame = document.getElementById("IndieHubFrame")
if (!indieHubFrame.src) {
indieHubFrame.src = host + "/hub" + location.search + "&ts=" + moment().unix()
indieHubFrame.contentWindow.addEventListener('load', function () {
}, false)
}
else {
replicateViaOpenChannel(n)
}
}
//- ftp : trigger /minddrive/save in opener with changes from editor
// TODO
/**
* - ftp : dead wood hostapp
if (window.hostapp) {
let ps = new URLSearchParams(location.search.substring(1))
let path = ps.get('p')
//- issue : add share checkbox to editor
window.hostapp.run('/minddrive/save', { path: path, share: share }, n)
//- ftp : ensure new text is setup for editing
opidox.rte.setup()
//- issue : show if saved and prevent reload if edited but not saved
$('#isSaved').prop('checked', true)
}
else {
alert('hostapp not set')
}
*/
}
_rte.createLink = function (text) {
if (text.startsWith("http")) {
return text;
}
else {
}
}
/**
*
* @param {*} prop propery name
* @returns
* - feat : opidox.rte.interpretPropOnPage
*/
_rte.getPropFromPage = function (prop) {
let value
let text = $('.rte-editbox').html()
let index = text.indexOf('- ' + prop + ' :')
//- fix : allow string values in property setting
if (index === -1) {
return
}
text = text.substring(index)
let indexEnd = text.indexOf('')
text = '' + text.substring(0, indexEnd) + '
'
value = $(text).children()
if (value.length === 0) {
let bit = $(text).text()
value = bit.substring(prop.length + 5)
}
let binding = {}
binding[prop] = value
return binding
}
_rte.cleanElem = function (sel) {
$(sel).toArray().forEach(function (elem, i) {
//- fix : do not remove attributes for elems with ids
while (elem.attributes.length > 0 && !elem.id)
elem.removeAttribute(elem.attributes[0].name);
})
}
_rte.removeNamedAttribute = function (sel, attr) {
$(sel).toArray().forEach(function (elem, i) {
elem.removeAttribute(attr);
})
}
_rte.removeSpans = function () {
}
_rte.interpretPropOnPage = function (prop) {
let propertyBinding = _rte.getPropFromPage(prop)
if (!propertyBinding[prop]) {
alert("no prop " + prop)
return
}
//- fix : interpreter not defined
let interpreter =
{
i: function (val) {
//- fn : setHeightOnImage
function setHeightOnImage() {
$('img', '.rte-editbox').height("32")
}
setHeightOnImage()
let imageSrc = val[0]['src']
//
console.log(n)
if (n.i !== imageSrc) {
n.i = imageSrc
_rte.save(n)
}
}
}
let f = interpreter[prop]
let a = propertyBinding[prop]
f(a)
}
_rte.getSelectionText =
function () {
var text = "";
var activeEl = document.activeElement;
var activeElTagName = activeEl ? activeEl.tagName.toLowerCase() : null;
if (
(activeElTagName == "textarea") || (activeElTagName == "input" &&
/^(?:text|search|password|tel|url)$/i.test(activeEl.type)) &&
(typeof activeEl.selectionStart == "number")
) {
text = activeEl.value.slice(activeEl.selectionStart, activeEl.selectionEnd);
} else if (window.getSelection) {
text = window.getSelection().toString();
}
return text;
}
return _rte;
})()
window.opidox.rte = opidox.rte
// introduce rte.munge.munge = (function () {
opidox.rte.munge = (function () {
let _munge = {}
_munge.section = function () {
let sections = $('section')
debugger
let backgroundImageUrl = $(sections[1]).css('background-image')
return backgroundImageUrl.substring(5,backgroundImageUrl.length-2)
}
return _munge
})()
opidox.rte.annote = (function () {
let pageUrl = "http://hsc.fed.wiki/view/hypertext-super-collaborator"
let _annote = {}
_annote.t = function () {
let frame = ``
}
return _annote
})()
opidox.rte.action = (function () {
let _action = {}
_action.autoSave = function () {
}
_action.createDot = function (title, stub) {
// let mg3 = mg2 || mg3
// let ns = parent.mg3.dot.byTitle(title, true);
//- ftp : restore opidox.rte.createDot
let ns = mindgraph.dot.byTitle(title, true)
if (!stub) {
stub = title
}
let n;
if (ns.length === 0) {
n = {
t: title,
s: stub,
i: 'https://bafybeihvcrddb4zbq5t4zuj7q4esabf5mizoxvkjvoac7gmmf73fcnqou4.ipfs.w3s.link/dot.png'
}
n = mindgraph.dot.createFromJSON(n)
}
else {
n = ns[0]
n.stub = stub
}
mindgraph.dot.save(n)
return n
}
return _action
})()
/**
* TrailMarker capabilities
*/
window.trailmarker = function () {
function doMark() {
// alert("not in use")
//https://stackoverflow.com/questions/1197401/get-element-node-at-caret-position-in-contenteditable
let currentNode = document.getSelection().anchorNode.parentNode
let currentHTML = currentNode.innerHTML + ' '
// let inputBox = ' '
let bit = currentNode.tagName === "LI" ?
currentNode.innerHTML = currentHTML + inputBox + ''
: currentHTML
let newBit = $('' + currentHTML + inputBox + '
')
if (currentNode.tagName !== 'LI') {
x = $(currentNode).after(newBit)
$(currentNode).remove()
$('input', newBit).focus()
}
else {
$('input', newBit).focus()
}
$('input').blur(function (ev) {
$(ev.target).replaceWith(ev.target.value)
})
}
function doSection() {
alert("Do Section")
doMark()
}
function doHash() {
alert('#')
}
function setupKeyHandlers() {
//- Q&D : block keyhandlers in editor
// https://medium.com/@albertogasparin/getting-plain-text-from-user-input-on-a-contenteditable-element-b711aba2cb36
// $('div').keydown(onKeyDown)
// $('li').keydown(onKeyDown)
//- issue : show if saved and prevent reload if edited but not saved
// unchecked isSaved chackbox on input
$('.rte-editbox').on('input', function (ev) {
$('#isSaved').prop('checked', '')
})
}
var _trm = {}
_trm.setup = setupKeyHandlers
let last = ''
function onKeyDown() {
let keyMap = {
187: '=',
189: '-',
32: ' ',
71: 'g',
72: 'h',
77: 'm',
222: '#'
}
let actionMap = {
"- ": doMark,
"= ": doSection,
" #": doHash
}
var key = window.event.keyCode;
console.log(key)
let handlerKey = keyMap[key]
console.log(handlerKey)
if (last) {
let action = actionMap[last + handlerKey]
if (action) {
(action)()
last = ''
}
}
if (handlerKey) {
last = handlerKey
}
return true;
}
return _trm
}()
/**
* https://codepen.io/davidkacha/pen/zzNBxq
*
* @param html
*/
function formatFactory(html) {
if (html === "undefined") {
return "
\n")
x.innerText = bit
})
}